package com.example.demo.controller;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.example.demo.config.PropertiesConfig;
import com.example.demo.service.AccessTokenService;
import com.example.demo.util.MessageUtil;
import com.google.gson.Gson;

@RestController
//@RequestMapping("test")
public class IndexController {
	
	protected final Logger logger= LoggerFactory.getLogger(getClass());
	
	private Gson gson = new Gson();
	
	@Autowired
	private RestTemplate restTemplate;
	
	@Autowired
	private PropertiesConfig propertiesConfig;
	
	@Autowired
	private AccessTokenService accessTokenService;

	/**
	 * 本服务主页，用于建立开发者中心开启回调URL，公众号后台启动开发者URL时会请求该方法并验证表单中的token信息。
	 * 
	 * @param paramsMap
	 * @return
	 */
	@GetMapping("")
	public Object helloWechat(@RequestParam Map<String, String> paramsMap) {
		Map<String, String> data = paramsMap;
		List<String> list = new ArrayList<String>();
		String signature = data.get("signature");
		String timestamp = data.get("timestamp");
		String nonce = data.get("nonce");
		String echostr = data.get("echostr");
		String token = "123456";
		try {
			if (StringUtils.isEmpty(timestamp) || StringUtils.isEmpty(nonce)) {
				throw new Exception("微信参数为空");
			}
			list.add(token);
			list.add(timestamp);
			list.add(nonce);
			Collections.sort(list);
			String string = list.get(0) + list.get(1) + list.get(2);

			System.out.println(string);
			String hashcode = DigestUtils.sha1Hex(string.getBytes());
			System.out.println("hashcode = " + hashcode);

			if (hashcode.equals(signature)) {
				System.out.println("验证成功");
				return echostr;
			} else {
				System.err.println("验证失败了");
				return "";
			}
		} catch (Exception e) {
			//e.printStackTrace();
			logger.error("异常{}",e.getMessage());
			paramsMap.put("message", "未接收到微信参数");
		}
		return "你好,本地程序运行着呢！接收微信参数 ：" + paramsMap +"，日期："+ new Date().toLocaleString();
	}

	/**
	 * 接收微信公众平台推送数据，并返回给微信公众平台xml结果；
	 * 如果已经关注了该公众号，当再次扫描公众号的二维码时则不会触发事件；
	 * 如果已经关注了该公众号，当再次扫描带参数二维码时则触发事件并进入对话界面；
	 * @param request
	 * @return
	 */
	@PostMapping(value = "")
	@ResponseBody
	public String postxml(HttpServletRequest request) {
		// 接收成功，返回xml数据
		String xml = "<xml>\r\n" 
				+ "	<ToUserName><![CDATA[{0}]]></ToUserName>\r\n"
				+ "	<FromUserName><![CDATA[{1}]]></FromUserName>\r\n" 
				+ "	<CreateTime>{2}</CreateTime>\r\n"
				+ "	<MsgType><![CDATA[text]]></MsgType>\r\n" 
				+ "	<Content><![CDATA[{3}]]></Content>\r\n"
				+ "</xml>";//返回的xml内容
		String result = "";
		String content = "";//返回文本内容
		String contentSuffix = "程序自动发送，不必回复";
		String contentSubscribe = "欢迎关注sectotal在线安全服务公众号";//关注时的回复信息
		try {
			String request2xml = MessageUtil.request2xml(request);
			System.out.println("接收的内容是<<<<<<<<<<");
			System.out.println(MessageUtil.formatXml(request2xml));
			Map<String, String> resultMap = MessageUtil.xmlToMap(request2xml);
			//eventKey对应sectotal userId
			//fromUserName对应wechat openid
			String toUserName = resultMap.get("ToUserName");
			String fromUserName = resultMap.get("FromUserName");
			String msgType = resultMap.get("MsgType");// 事件类型
			String event = resultMap.get("Event");// 事件类型
			String eventKey = resultMap.get("EventKey");// 创建二维码时的二维码scene（场景值）
			String ticket = resultMap.get("Ticket");// 二维码的ticket，可用来换取二维码图片
			// 消息管理：接收普通消息
			if("text".equals(msgType) 
					|| "image".equals(msgType)
					|| "voice".equals(msgType)
					|| "video".equals(msgType)
					|| "music".equals(msgType)
					|| "news".equals(msgType)) {
				logger.info("消息对话，来自openid={}\t{}",fromUserName,resultMap.get("Content"));
				//return "success";//对于普通消息不做任何回复，此处可返回"success"或空字符串""
			}			
			// 关注、取消关注（不区分扫码关注还是搜索公众号名称关注）
			if(StringUtils.isNotEmpty(msgType)
					&& StringUtils.isNotEmpty(event)
					&& StringUtils.isEmpty(eventKey)
					&& StringUtils.isEmpty(ticket)) {
				if("event".equals(msgType) && "subscribe".equals(event)) {//关注账号
					logger.info("微信openid={}关注公众号",fromUserName);
					content = contentSubscribe+"（"+contentSuffix+"！）";
				}else if("event".equals(msgType) && "unsubscribe".equals(event)) {//取消关注
					logger.info("微信openid={}取消关注公众号",fromUserName);
					//从mongo里面删除userId与openid关系
					//TODO 如果只是关注微信公众号，但从未设置userId与openid关联则无法删除userId与openid关系
					Boolean isBanding = false;//设置关联解除
					//取消关注公众号同时解绑userId与openid，无论是否成功，此时不回复任何信息
					bandingWechat(isBanding,fromUserName,eventKey);
				}
			}
			// 扫描带参数二维码事件
			if (StringUtils.isNotEmpty(msgType) 
					&& StringUtils.isNotEmpty(event) 
					&& StringUtils.isNotEmpty(eventKey)
					&& StringUtils.isNotEmpty(ticket)) {
				////设置sectotal userId与wechat openid关联关系，但是未关注和已关注情况下扫描带参数二维码时的EventKey格式是不同的，区别如下
				//未关注：<EventKey><![CDATA[qrscene_ea8ca659f440498c93d78519190573bd]]></EventKey>
				//已关注：<EventKey><![CDATA[ea8ca659f440498c93d78519190573bd]]></EventKey>
				if ("event".equals(msgType) && "subscribe".equals(event)) {// 用户未关注时，进行关注后的事件推送
					eventKey = eventKey.replace("qrscene_", "");//删除冗余的前缀，只保留场景值
					Boolean isBanding = true;//设置关联
					content = bandingWechat(isBanding,fromUserName,eventKey);
					content = contentSubscribe +"\n"+ content + "，"+contentSuffix+"！";
					logger.info("微信openid={}扫码带参数二维码关注公众号同时进行微信关联，结果{}",fromUserName,content);
				} else if ("event".equals(msgType) && "SCAN".equals(event)) {// 用户已关注时的事件推送
					Boolean isBanding = true;//设置关联
					content = bandingWechat(isBanding,fromUserName,eventKey);
					content = content + "，"+contentSuffix+"！";
					logger.info("微信openid={}扫码带参数二维码进行微信关联，结果{}",fromUserName,content);
				}
			}
			if(StringUtils.isNotEmpty(content)) {
				String CreateTime = System.currentTimeMillis() + "";
				result = MessageFormat.format(xml, fromUserName, toUserName, CreateTime, content);
			}else {
				result = "success";
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("返回的内容是>>>>>>>>>>");
		System.out.println(result);
		return result;
	}
	
	public String bandingWechat(Boolean isBanding,String openid,String userId) {
		logger.info("isBanding={}，openid={}，userId={}",isBanding,openid,userId);
		//获取微信accesstoken
		String accessToken = accessTokenService.findById(propertiesConfig.getAppId()).get().getAccessToken();
		//获取微信用户基本信息
		String tempUrlUserInfo = propertiesConfig.getUrlUserInfo();
		String urlUserInfo = MessageFormat.format(tempUrlUserInfo, accessToken,openid);
		Map<String,Object> apiResultUserInfo = new HashMap<String, Object>();
		try {
			apiResultUserInfo = restTemplate.getForObject(urlUserInfo, Map.class);
		} catch (Exception e) {
			return "远程接口失败，微信用户基本信息接口，"+urlUserInfo+"，"+e.getMessage();
		}
		String wechatUser = gson.toJson(apiResultUserInfo);
		//将微信openid与sectotal username进行绑定
		String tempUrlBangdingOpenId = propertiesConfig.getUrlBangdingOpenId();
		String urlBangdingOpenId = MessageFormat.format(tempUrlBangdingOpenId, isBanding,openid,userId);
		Map<String,Object> apiResultBangding = new HashMap<String, Object>();
		HttpHeaders httpHeaders = new HttpHeaders();
		httpHeaders.add("Content-Type", "application/json");
		HttpEntity<String> httpEntity = new HttpEntity<String>(wechatUser,httpHeaders);
		try {
			apiResultBangding = restTemplate.postForObject(urlBangdingOpenId,httpEntity, Map.class);
		} catch (Exception e) {
			return "远程接口失败，用户绑定openid接口，"+urlBangdingOpenId+"，"+e.getMessage();
		}
		int code = (int)apiResultBangding.get("code");
		if(isBanding) {
			if(code == 20000) {//设置成功
				Map tempUserMap = (Map)apiResultBangding.get("data");
				String username = (String)tempUserMap.get("username");
				String nickname = (String)apiResultUserInfo.get("nickname");
				String content = "微信推送设置成功（系统用户："+username+"，微信用户："+nickname+"）";//username、openid、微信昵称
				return content;
			}else {
				String message = (String)apiResultBangding.get("message");
				String content = "微信关联失败，"+message;
				return content;
			}
		}else {//解绑userId与openid时不返回日志
			return null;
		}
	}

}
